/*******************************************************************************
 * Jimm - Mobile Messaging - J2ME ICQ clone
 * Copyright (C) 2003-05  Jimm Project
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *getName
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 ********************************************************************************
 * File: src/jimm/modules/photo/ViewFinder.java
 * Version: ###VERSION###  Date: ###DATE###
 * Author(s): Andreas Rossbacher, Dmitry Tunin, Vladimir Kryukov
 *******************************************************************************/

// #sijapp cond.if modules_FILES="true"#
// #sijapp cond.if modules_ANDROID isnot "true"# //add android fs
package jimm.modules.photo;

import DrawControls.text.*;
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import jimm.*;
import jimm.cl.ContactList;
import jimm.comm.Util;
import jimm.modules.*;
import jimm.ui.base.*;
import jimm.util.JLocale;

/** ************************************************************************* */
/** ************************************************************************* */
// Class for viewfinder
public class ViewFinder extends Canvas implements Runnable {
    // Variables
    private Player player = null;
    private VideoControl videoControl = null;
    private Par errorMessage = null;
    private byte[] data;
    
    private static final byte STATE_CAPTURE = 0;
    private static final byte STATE_PREEVIEW = 1;
    private static final byte STATE_ERROR = 2;
    private byte state = STATE_CAPTURE;
    private static int takePhotoMethod = 0;
    private Image thumbnailImage = null;
    
    private PhotoListener listener;
    private GraphicsEx gx = new GraphicsEx();
    // #sijapp cond.if modules_TOUCH is "true"#
    private int touchKey = 0;
    private int touchStartX = 0;
    // #sijapp cond.end#

    private static int useSize = 0;
    private static final String[] sizes = {"", "320x240",
            "480x640", "640x480",
            "1280x960", "2048x1536"};
    private static final String[] keys = {"", "width=320&height=240",
            "width=480&height=640", "width=640&height=480",
            "width=1280&height=960", "width=2048&height=1536"};
    
    public void show() {
        setFullScreenMode(true);
        Jimm.getJimm().getDisplay().show(this);
        start();
    }
    public void setPhotoListener(PhotoListener l) {
        listener = l;
    }
    private void back() {
        dismiss();
        Jimm.getJimm().getDisplay().back(this);
    }
    
    public ViewFinder() {
    }
    private void setError(JimmException err) {
        state = STATE_PREEVIEW;
        Parser parser = new Parser(-1, GraphicsEx.contactListFontSet, getWidth() * 8 / 10);
        byte color = CanvasEx.THEME_CAP_TEXT;
        if (0 < (gx.getThemeColor(CanvasEx.THEME_CAP_TEXT) & 0x808080)) {
            color = CanvasEx.THEME_CAP_BACKGROUND;
        }
        parser.addText(err.getMessage(), color, CanvasEx.FONT_STYLE_PLAIN);
        errorMessage = parser.getPar();
        repaint();
    }
    
    public void paint(Graphics g) {
        gx.setGraphics(g);
        int captionHeight = GraphicsEx.calcCaptionHeight(null, "");
        int softBarHeight = gx.getSoftBarSize();
        int width = getWidth();
        int height = getHeight() - softBarHeight - captionHeight;
        String caption = (STATE_CAPTURE == state) ? "viewfinder" : "send_img";
        caption = JLocale.getString(caption);
        if (0 < useSize) {
            caption += " " + sizes[useSize];
        }

        gx.drawBarBack(0, captionHeight, Scheme.captionImage);
        gx.drawCaption(null, caption, null, captionHeight);
        g.setColor(0xffffffff);
        g.fillRect(0, captionHeight, width, height);

        g.setColor(0x00000000);
        if (STATE_PREEVIEW == state) {
            if (null != errorMessage) {
                errorMessage.paint(GraphicsEx.contactListFontSet, gx, width / 10,
                        (height - errorMessage.getHeight()) / 2,
                        0, errorMessage.getHeight());

            } else if (null != thumbnailImage) {
                g.drawImage(thumbnailImage, width / 2, height / 2, Graphics.VCENTER | Graphics.HCENTER);

            } else {
                g.drawString("...", width / 2 - 5, height / 2, Graphics.TOP | Graphics.LEFT);
            }
        }
        gx.drawSoftBar((null == errorMessage) ? JLocale.getString("ok") : "",
                "",
                JLocale.getString("back"), softBarHeight);
    }
    
    private void createPlayer(String url) throws IOException, MediaException {
        player = Manager.createPlayer(url);
        player.realize();
        videoControl = (VideoControl) player.getControl("VideoControl");
    }
    
    private void initVideo() throws JimmException {
        thumbnailImage = null;
        data = null;
        try {
            // Create the player
            // #sijapp cond.if target is "MIDP2" #
            try {
                if (Jimm.isPhone(Jimm.PHONE_NOKIA_S40)) {
                    createPlayer("capture://image");
                }
            } catch (Exception e) {
            }
            // #sijapp cond.end #
            if (null == videoControl) {
                createPlayer("capture://video");
            }
            if (null == videoControl) {
                throw new JimmException(180, 0);
            }
            videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, this);
            
            int captionHeight = GraphicsEx.calcCaptionHeight(null, "");
            int softBarHeight = gx.getSoftBarSize();
            int canvasWidth = getWidth();
            int canvasHeight = getHeight() - softBarHeight - captionHeight;
            try {
                videoControl.setDisplayLocation(0, captionHeight);
                videoControl.setDisplaySize(canvasWidth, canvasHeight);
            } catch (MediaException me) {
                try {
                    videoControl.setDisplayFullScreen(true);
                } catch (MediaException me2) {
                }
            }
            int displayWidth  = videoControl.getDisplayWidth();
            int displayHeight = videoControl.getDisplayHeight();
            int x = (canvasWidth - displayWidth) / 2;
            int y = captionHeight + (canvasHeight - displayHeight) / 2;
            
            videoControl.setDisplayLocation(x, y);
            
            videoControl.setVisible(true);
            player.start();
        } catch (IOException ioe) {
            // #sijapp cond.if modules_DEBUGLOG is "true" #
            DebugLog.panic("initVideo (ioe)", ioe);
            // #sijapp cond.end#
            throw new JimmException(181, 0);
        }  catch (MediaException me) {
            // #sijapp cond.if modules_DEBUGLOG is "true" #
            DebugLog.panic("initVideo (me)", me);
            // #sijapp cond.end#
            throw new JimmException(181, 1);
        }  catch (SecurityException se) {
            throw new JimmException(181, 2);
        }  catch (Exception e) {
            // #sijapp cond.if modules_DEBUGLOG is "true" #
            DebugLog.panic("initVideo (e)", e);
            // #sijapp cond.end#
            throw new JimmException(181, 3);
        }
    }
    // start the viewfinder
    private void start() {
        stop();
        try {
            initVideo();
            state = STATE_CAPTURE;
        }  catch (JimmException e) {
            stop();
            setError(e);
        }
    }
    
    // stop the viewfinder
    private void stop() {
        if (null != videoControl) {
            try {
                videoControl.setVisible(false);
                // Remove video control at SE phones placing it beyond screen border
                // #sijapp cond.if target is "MIDP2" #
                if (Jimm.isPhone(Jimm.PHONE_SE)) {
                    videoControl.setDisplayLocation(1000, 1000);
                }
                // #sijapp cond.end #
            } catch (Exception e) {
            }
        }
        videoControl = null;
        
        if (null != player) {
            try {
                if (Player.STARTED == player.getState()) {
                    player.stop();
                }
                player.close();
            } catch (Exception e) {
            }
        }
        player = null;
        System.gc();
    }
    
    private byte[] getSnapshot(String type) {
        try {
            return videoControl.getSnapshot(type);
        } catch (SecurityException e) {
            return null;
        } catch (Exception e) {
            // #sijapp cond.if modules_DEBUGLOG is "true" #
            //DebugLog.panic("getSnapshot(" + type + ")", e);
            // #sijapp cond.end#
            takePhotoMethod++;
            return null;
        }
    }
    
    // take a snapshot form the viewfinder
    public void takeSnapshot() {
        if (null != player) {
            data = null;
            //"&width=" + this.res[0][this.res_marker] + "&height=" + this.res[1][this.res_marker]
            if (0 < useSize) {
                data = getSnapshot("encoding=jpeg&" + keys[useSize]);
            }
            switch (takePhotoMethod) {
                case 0: if (null == data) data = getSnapshot("encoding=jpeg&width=320&height=240");
                case 1: if (null == data) data = getSnapshot("encoding=jpeg&width=480&height=640");
                case 2: if (null == data) data = getSnapshot("encoding=jpeg&width=640&height=480");
                case 3: if (null == data) data = getSnapshot("encoding=jpeg");
                case 4: if (null == data) data = getSnapshot("JPEG");
            }
            if (null == data) data = getSnapshot(null);
            
            state = STATE_PREEVIEW;
            stop();
            repaint();
            if (null == data) {
                setError(new JimmException(183, 0));

            } else {
                Image img = Image.createImage(data, 0, data.length);
                thumbnailImage = Util.createThumbnail(img, getWidth(), getHeight());
                repaint();
            }
        }
    }
    public void dismiss() {
        stop();
        data = null;
        thumbnailImage = null;
        listener = null;
    }
    
    public void run() {
        takeSnapshot();
    }
    
    protected void keyPressed(int key) {
        // #sijapp cond.if modules_LIGHT is "true" #
        CustomLight.setLightMode(CustomLight.ACTION_KEY_PRESS);
        // #sijapp cond.end#
        int keyCode = NativeCanvas.getJimmKey(key);
        int action = NativeCanvas.getJimmAction(keyCode, key);
        doKeyPressed(keyCode, action);
    }
    
    // #sijapp cond.if modules_TOUCH is "true"#
    private int getTouchKey(int x) {
        switch (x / (getWidth() / 3)) {
            case 0: return NativeCanvas.LEFT_SOFT;
            case 1: return NativeCanvas.NAVIKEY_FIRE;
            case 2: return NativeCanvas.RIGHT_SOFT;
        }
        return 0;
    }
    protected void pointerReleased(int x, int y) {
        ContactList.getInstance().userActivity();        
        if (y > getClientHeight()) {
            final int key = getTouchKey(x);
            if (key == touchKey) {
                doKeyPressed(key, key);
            }
        } else {
            int delta = x - touchStartX;
            if (getWidth() / 3 < Math.abs(delta)) {
                final int key = (delta < 0) ? NativeCanvas.NAVIKEY_LEFT
                        : NativeCanvas.NAVIKEY_RIGHT;
                doKeyPressed(key, key);
            }
        }
        
        touchKey = 0;
    }
    protected void pointerPressed(int x, int y) {
        ContactList.getInstance().userActivity();
        // #sijapp cond.if modules_LIGHT is "true" #
        CustomLight.setLightMode(CustomLight.ACTION_KEY_PRESS);
        // #sijapp cond.end#
        touchKey = (y < getClientHeight()) ? 0 : getTouchKey(x);
        touchStartX = x;
    }
    protected void pointerDragged(int x, int y) {
        // #sijapp cond.if modules_LIGHT is "true" #
        CustomLight.setLightMode(CustomLight.ACTION_KEY_PRESS);
        // #sijapp cond.end#
    }
    private int getClientHeight() {
        return getHeight() - gx.getSoftBarSize();
    }
    // #sijapp cond.end#    
            
    // Key pressed
    public void doKeyPressed(int keyCode, int actionCode) {
        if ((STATE_CAPTURE == state) && (NativeCanvas.CAMERA_KEY == actionCode)) {
            actionCode = NativeCanvas.NAVIKEY_FIRE;
        }
        switch (actionCode) {
            case NativeCanvas.RIGHT_SOFT:
            case NativeCanvas.CLOSE_KEY:
                if ((STATE_CAPTURE == state) || (null != errorMessage)) {
                    stop();
                    back();
                    
                } else {
                    state = STATE_CAPTURE;
                    start();
                }
                break;
                
            case NativeCanvas.LEFT_SOFT:
            case NativeCanvas.NAVIKEY_FIRE:
                if (STATE_CAPTURE == state) {
                    state = STATE_PREEVIEW;
                    new Thread(this).start();
                    
                } else if (null != thumbnailImage) {
                    stop();
                    try {
                        listener.processPhoto(data);
                        dismiss();
                    } catch (Exception e) {
                        setError(new JimmException(191, 4));
                    }
                }
                break;
                
            case NativeCanvas.NAVIKEY_LEFT:
                useSize = (useSize - 1 + sizes.length) % sizes.length;
                repaint();
                break;
                
            case NativeCanvas.NAVIKEY_RIGHT:
                useSize = (useSize + 1) % sizes.length;
                repaint();
                break;
        }
    }
}
// #sijapp cond.end#                             //add android fs
// #sijapp cond.end #
